unit PingPongAction;

{$IFDEF FPC}
  {$MODE Delphi}{$H+}
{$ENDIF}

interface

uses Actors, SysUtils, Variants, Windows;

type
  PPingPongParam = ^TPingPongParam;
  TPingPongParam = packed record
    Rounds: Integer;
    Limit: Integer;
    Verbose: boolean;
    Ticks: Cardinal;
    SimulateProcess: boolean;    
  end;

  TPingPong = class(TActor)
  public
    procedure Ping(Param: PActParam);
    procedure Pong(Param: PActParam);
  end;

  TPong = class;

  TPing = class(TActor)
  private
    FPong: TPong;
  public
    procedure Ping(Param: PActParam);
    property Pong: TPong read FPong write FPong;
  end;

  TPong = class(TActor)
  private
    FPing: TPing;
  public
    procedure Pong(Param: PActParam);
    property Ping: TPing read FPing write FPing;
  end;

implementation

procedure TPingPong.Ping(Param: PActParam);
begin
  // 0:Current, 1:Total, 2:ShowText, 3:StartTime,
  with PPingPongParam(Param^)^ do
  begin
    if Verbose then
      Writeln('Ping(', Rounds, '/', limit, ')');
    //Send(Pong, Pong.Pong, Param);
    Send(Pong, Param);
    if SimulateProcess then
      Sleep(1000);
  end;
end;

procedure TPingPong.Pong(Param: PActParam);
var
  t: Integer;
begin
  // 0:Current, 1:Total, 2:ShowText, 3:StartTime,
  with PPingPongParam(Param^)^ do
  begin
    if Verbose then
      Writeln('Pong(', Rounds, '/', limit, ')');
    Dec(Rounds);
    if Rounds > 0 then
    begin
      //Send(Ping, Ping.Ping, Param);
      Send(Ping, Param);
      if SimulateProcess then
        Sleep(1000);
    end else
    begin
      t := GetTickCount-Ticks+1;
      Writeln(Format('PingPong(%d): %d (%0.n Rounds/sec)', [Limit,t, (Limit*1000/t)]));
    end;
  end;
end;

{ TPing }

procedure TPing.Ping(Param: PActParam);
begin
  // 0:Current, 1:Total, 2:ShowText, 3:StartTime,
  with PPingPongParam(Param^)^ do
  begin
    if Verbose then
      Writeln('Ping(', Rounds, '/', limit, ')');
    Send(Pong, Pong.Pong, Param);
    //Send(Pong, Param);
    if SimulateProcess then
      Sleep(1000);
  end;
end;

{ TPong }

procedure TPong.Pong(Param: PActParam);
var
  t: Integer;
begin
  // 0:Current, 1:Total, 2:ShowText, 3:StartTime,
  with PPingPongParam(Param^)^ do
  begin
    if Verbose then
      Writeln('Pong(', Rounds, '/', limit, ')');
    Dec(Rounds);
    if Rounds > 0 then
    begin
      Send(Ping, Ping.Ping, Param);
      //Send(Ping, Param);
      if SimulateProcess then
        Sleep(1000);
    end else
    begin
      t := GetTickCount-Ticks+1;
      Writeln(Format('PingPong(%d): %d (%0.n Rounds/sec)', [Limit,t, (Limit*1000/t)]));
    end;
  end;
end;

end.